/*
 * Copyright (c) 2002-2003 by OpenSymphony
 * All rights reserved.
 */
package org.jackysoft.entity;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;








import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Element;
import org.dom4j.tree.DefaultElement;
import org.jackysoft.annotations.Transient;
import org.jackysoft.entity.base.AbstractRootEntity;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

/**
 * User: hani Date: May 28, 2003 Time: 12:44:54 AM
 */


public abstract class AbstractNode extends AbstractRootEntity {
	protected static final Log logger = LogFactory.getLog(AbstractNode.class);
	/**
	 * 
	 */
	private static final long serialVersionUID = -5961490844478392548L;
	// ~ Instance fields
	// ////////////////////////////////////////////////////////

	protected AbstractNode parent;

	protected int id;
	protected Element element;	
	
	public AbstractNode() {
		super();
	}

	public AbstractNode(Element root) {
		this.element = root;
		this.init(root);
	}

	protected void addargs(Element root, Map<String, String> args) {
		childmap(root, args, "arg");
	}

	protected <T extends AbstractNode> void addchild(Element root, T field) {
		if (root != null && field != null)
			root.add(field.asElement());
	}

	protected <T extends AbstractNode> void addchildren(Element root,
			Collection<T> values) {
		if (root != null && values != null && !values.isEmpty()) {
			for (T t : values) {
				if (t.asElement() != null) {
					root.add(t.asElement());
				}
			}
		}
	}

	protected void addmetas(Element root, Map<String, String> metas) {
		childmap(root, metas, "meta");
	}

	protected Map<String, String> args(Element root) {
		Map<String, String> args = Maps.newHashMap();
		Iterator itr = root.elementIterator("arg");
		for (; itr != null && itr.hasNext();) {
			Element child = (Element) itr.next();
			if (child != null) {
				args.put(child.attributeValue("name"), child.getTextTrim());
			}
		}
		return args;
	}

	public abstract Element asElement();

	public String asXML() {

		if (this.element != null)
			return this.element.asXML();
		else {
			if (this.asElement() != null) {
				return this.asElement().asXML();
			}
		}
		return "";
	}

	protected void attr(Element root, String name, Boolean value) {
		if (root != null && value != null)
			root.addAttribute(name, String.valueOf(value));
	}

	protected void attr(Element root, String name, Integer value) {
		if (root != null && value != null)
			root.addAttribute(name, String.valueOf(value));
	}

	protected void attr(Element root, String name, String value) {
		if (root != null && !StringUtils.isEmpty(value))
			root.addAttribute(name, value);
	}

	protected void attrid(Element root) {
		attr(root, "id", id);
	}

	protected void attrtrue(Element root, String name, Boolean value) {
		if (root != null && value != null && value) {
			attr(root, name, value);
		}
	}

	protected Boolean booleanAttr(Element root, String pname) {
		return Boolean.parseBoolean(root.attributeValue(pname));
	}

	private void childmap(Element root, Map<String, String> values,
			String tagName) {
		if (root != null && values != null && !values.isEmpty()
				&& !StringUtils.isEmpty(tagName)) {
			for (Map.Entry<String, String> entry : values.entrySet()) {
				Element child = root.addElement(tagName);
				attr(child, "name", entry.getKey());
				text(child, entry.getValue());
			}
		}
	}

	protected <T extends AbstractNode> T childof(Element root, String tagName,
			Class<T> type) {
		Element child = root.element(tagName);
		T tins = null;
		if (child != null) {
			try {
				Constructor<T> ct = type.getConstructor(Element.class);
				tins = ct.newInstance(child);
			} catch (NoSuchMethodException | SecurityException
					| InstantiationException | IllegalAccessException
					| IllegalArgumentException | InvocationTargetException e) {
				// logger.error(e);
				e.printStackTrace();
			}

		}
		return tins;
	}

	protected <T extends AbstractNode> Collection<T> childrenof(Element root,
			String tagName, Class<T> type) {
		Iterator itr = root.elementIterator(tagName);
		final Collection<T> arrs = Lists.newArrayList();
		try {
			for (; itr != null && itr.hasNext();) {
				Element child = (Element) itr.next();
				if (child == null)
					continue;
				Constructor<T> con = type.getConstructor(Element.class);
				T t = con.newInstance(child);
				arrs.add(t);
			}

		} catch (NoSuchMethodException | InstantiationException
				| IllegalAccessException | IllegalArgumentException
				| InvocationTargetException e) {
			e.printStackTrace();
		}

		return arrs;
	}

	protected Element elementof(String qname) {
		Element ele;
		if (!StringUtils.isEmpty(qname)) {
			ele = new DefaultElement(qname);
			attrid(ele);
			return ele;
		}
		throw new IllegalArgumentException("参数 qname 不能为空");
	}

	
	
	public int getId() {
		return id;
	}

	@Transient
	public AbstractNode getParent() {
		return parent;
	}

	protected abstract void init(Element adc);

	protected int intAttr(Element root, String pname) {
		String id = root.attributeValue(pname);
		return id == null ? 0 : Integer.parseInt(id);
	}

	protected Map<String, String> metas(Element root) {
		Iterator metas = root.elementIterator("meta");
		Map<String, String> values = Maps.newHashMap();
		for (; metas != null && metas.hasNext();) {
			Element meta = (Element) metas.next();
			values.put(meta.attributeValue("name"), meta.getTextTrim());
		}
		return values;
	}

	public void setId(int id) {
		this.id = id;

	}

	public void setParent(AbstractNode parent) {
		this.parent = parent;
	}

	/************************************************/
	// //
	/************************************************/

	protected String stringAttr(Element root, String pname) {
		return root.attributeValue(pname);
	}

	protected void text(Element root, String text) {
		if (root != null && !StringUtils.isEmpty(text))
			root.addText(text);
	}

	public abstract String tagName();	

}
